简化循环和逻辑

一、流程控制

1. 判断

1)条件判断中的参数顺序

比较的左侧 比较的右侧
“被问询的”表达式,更倾向于不断变化 用来做比较的表达式,它的值更倾向于常量

PS:但是反着写,能够避免掉那种if(obj = NULL)的错误,俗称“尤达表示法”。

2)if/else 语句块的顺序

三个倾向性:

  1. 倾向于先处理正逻辑,再处理负逻辑
  2. 倾向于先处理掉简单情况
  3. 倾向于先处理掉有趣的或者可疑的状况

3)?:条件表达式

  • 并不是很推荐这种写法哈哈哈哈,一旦写了长表达式,就会很难理解

2. 循环

1)避免使用 do/while 循环

通常,逻辑条件应该出现在它们所“保护”的代码前。而且do/while循环中的continue会产生歧义。

2)最小化嵌套

深嵌套会让读者的“思维栈”太深,可以通过提早返回来减少嵌套,可以将代码进行如下变化:

1
2
3
4
5
6
7
8
9
if (a) {
if (b) {
// do something 1
return;
}
// do something 2
}
// do something 3
return;
1
2
3
4
5
6
7
8
9
10
if (!a) {
// do something 3
return;
}
if (b) {
// do something 1
return;
}
// do something 2
return;

二、长表达式拆分

  • 方法一:增加变量:总结为一句话,用额外的变量,来代替一个长表达式,例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 解释变量
    if (line.split(":")[0].strip() == "root") {
    // ...
    }
    // **************************************
    // ↓
    // **************************************
    var userName = line.split(":")[0].strip();
    if (username == "root") {
    // ...
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // 总结变量
    if (request.user.id == document.owner_id) {
    // ...
    }
    // ...
    if (request.user.id != document.owner_id) {
    // ...
    }
    // ***********************************************************
    // ↓
    // ************************************************************
    var user_owns_document = request.user.id == document.owner_id;
    if (user_owns_document) {
    // ...
    }
    if (!user_owns_document) {
    // ...
    }
  • 方法二:使用德摩根定律

    • !(a || b || c) <=> (!a) && (!b) && (!c)
    • !(a && b && c) <=> (!a) || (!b) || (!c)
  • 方法三:不要滥用短路逻辑:短路逻辑可能会增加代码的理解难度。

  • 方法四:找到更优雅的方式,一个理念是:

    开始还很简单的问题变得非常令人费解,通常预示着一中更简单的方法。

  • 方法五:拆分巨大的语句,把一样的表达式抽离出来作为函数开头的总结变量

    • DRY:Don’t Repeat Yourself.

三、变量

关于变量的三个问题:

  • 变量越多,就越难全部追踪
  • 变量作用域越大,就需要跟踪的越久
  • 变量改变越频繁,就越难追踪它的当前值

1)减少变量

针对第一个问题,我们提出了以下几种方案,可以去掉以下几种不必要的变量:

  • 没有价值的临时变量:举个例子:now = datetime.datetime.now(),一般这种变量有以下几种特点,

    • 没有拆分任何临时变量
    • 没有做过多澄清,datetime.now()已经足够清晰
    • 只用一次(或少数几次),没有压缩任何冗余的代码
  • 中间结果:下面例子中,index_to_remove可以被移除,那些为了保存临时结果,用完即丢的变量,可以考虑丢弃:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var remove_one = function (array, value_to_remove) {
var index_to_remove = null;
for (var i = 0; i < array.length; i++) {
if (array[i] == value_to_remove) {
index_to_remove = i;
break;
}
}
if (index_to_remove !== null) {
array.splice(index_to_remove, 1);
}
};
// ***********************************************
// ↓
// ***********************************************
var remove_one = function (array, value_to_remove) {
var index_to_remove = null;
for (var i = 0; i < array.length; i++) {
if (array[i] == value_to_remove) {
array.splice(i, 1);
return;
}
}
};
  • 流程控制变量:用来控制流程的变量,往往不包含任何程序内的数据,能通过结构化编程来消除。

2)缩小变量作用域

让你的变量对尽量少的代码行可见。

  • 一个做法就是让变量“降级”,尽量降低作用域,比如

    • 类成员变量降级成某个成员函数中的局部变量
    • 运用好C++的块级作用域,那些仅仅用来当做判断条件的变量,可以放在if语句中定义:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    PaymentInfo* info = database.ReadPaymentInfo()
    if(info){
    // ...
    }
    // ************************************************
    // ↓
    // ************************************************
    if(PaymentInfo* info = database.ReadPaymentInfo()){
    // ...
    }
    • JavaScript的立即执行函数制造封闭的作用域
  • 定义下移:将定义移动到使用它之前,增加可读性

3)只写一次的变量更好

尽量减少对变量的赋值的语句,有助于提高可读性。